 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.forms.editor;

 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IKeyBindingService;
 import org.eclipse.ui.INestableKeyBindingService;
 import org.eclipse.ui.forms.IFormPart;
 import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.ManagedForm;
 import org.eclipse.ui.forms.widgets.ScrolledForm;
 import org.eclipse.ui.internal.forms.widgets.FormUtil;
 import org.eclipse.ui.internal.services.INestable;

 /**
  * A variation of {@link FormEditor}, this editor has a stable header that does
  * not change when pages are switched. Pages that are added to this editor
  * should not have the title or image set.
  *
  * @since 3.3
  */
 public abstract class SharedHeaderFormEditor extends FormEditor {
     private HeaderForm headerForm;
     
     private boolean wasHeaderActive= true;
     private Listener activationListener= null;

     private static class HeaderForm extends ManagedForm {
         public HeaderForm(FormEditor editor, ScrolledForm form) {
             super(editor.getToolkit(), form);
             setContainer(editor);
             if (editor.getEditorInput() != null)
                 setInput(editor.getEditorInput());
         }

         private FormEditor getEditor() {
             return (FormEditor) getContainer();
         }

         public void dirtyStateChanged() {
             getEditor().editorDirtyStateChanged();
         }

         public void staleStateChanged() {
             refresh();
         }
     }

     /**
      * The default constructor.
      */

     public SharedHeaderFormEditor() {
     }

     /**
      * Overrides <code>super</code> to create a form in which to host the tab
      * folder. This form will be responsible for managing
      *
      * @param parent
      * the page container parent
      *
      * @see org.eclipse.ui.part.MultiPageEditorPart#createPageContainer(org.eclipse.swt.widgets.Composite)
      */

     protected Composite createPageContainer(Composite parent) {
         parent = super.createPageContainer(parent);
         parent.setLayout(new FillLayout());
         ScrolledForm scform = getToolkit().createScrolledForm(parent);
         scform.getForm().setData(FormUtil.IGNORE_BODY, Boolean.TRUE);
         headerForm = new HeaderForm(this, scform);
         createHeaderContents(headerForm);
         return headerForm.getForm().getBody();
     }

     /**
      * Returns the form that owns the shared header.
      *
      * @return the shared header
      */

     public IManagedForm getHeaderForm() {
         return headerForm;
     }
     
     protected void createPages() {
         super.createPages();
         
         // preempt MultiPageEditorPart#createPartControl(Composite)
 if (getActivePage() == -1) {
             // create page control and initialize page, keep focus on header by calling super implementation
 super.setActivePage(0);
         }
     }
     
     protected void setActivePage(int pageIndex) {
         // programmatic focus change
 wasHeaderActive= false;
         super.setActivePage(pageIndex);
     }
     
     public void setFocus() {
         installActivationListener();
         if (wasHeaderActive)
             ((ManagedForm) getHeaderForm()).setFocus();
         else {
             int index= getActivePage();
             if (index == -1)
                 ((ManagedForm) getHeaderForm()).setFocus();
             else
                 super.setFocus();
         }
     }
     
     private void installActivationListener() {
         if (activationListener == null) {
             activationListener = new Listener() {
                 public void handleEvent(Event event) {
                     boolean wasHeaderActive = event.widget != getContainer();
                     
                     // fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=177331
 int activePage = getActivePage();
                     if (SharedHeaderFormEditor.this.wasHeaderActive != wasHeaderActive && activePage != -1 && pages.get(activePage) instanceof IEditorPart) {
                         IEditorPart activePart = (IEditorPart) pages.get(activePage);
                         IKeyBindingService keyBindingService = getSite().getKeyBindingService();
                         
                         if (wasHeaderActive) {
                             
                             if (activePart.getSite() instanceof INestable)
                                 ((INestable) activePart.getSite()).deactivate();
                             
                             if (keyBindingService instanceof INestableKeyBindingService)
                                 ((INestableKeyBindingService) keyBindingService).activateKeyBindingService(null);
                             
                         } else {
                             
                             if (keyBindingService instanceof INestableKeyBindingService)
                                 ((INestableKeyBindingService) keyBindingService).activateKeyBindingService(activePart.getSite());
                             
                             if (activePart.getSite() instanceof INestable)
                                 ((INestable) activePart.getSite()).activate();
                             
                         }
                     }
                     
                     SharedHeaderFormEditor.this.wasHeaderActive = wasHeaderActive;
                 }
             };
             getContainer().addListener(SWT.Activate, activationListener);
             getHeaderForm().getForm().getForm().getHead().addListener(SWT.Activate, activationListener);
         }
     }
     
     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.forms.editor.FormEditor#dispose()
      */
     public void dispose() {
         if (headerForm != null) {
             headerForm.dispose();
             headerForm = null;
         }
         super.dispose();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.forms.editor.FormEditor#isDirty()
      */
     public boolean isDirty() {
         return headerForm.isDirty() || super.isDirty();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.forms.editor.FormEditor#commitPages(boolean)
      */
     protected void commitPages(boolean onSave) {
         if (headerForm != null && headerForm.isDirty())
             headerForm.commit(onSave);
         super.commitPages(onSave);
     }

     /**
      * Subclasses should extend this method to configure the form that owns the
      * shared header. If the header form will contain controls that can change
      * the state of the editor, they should be wrapped in an IFormPart so that
      * they can participate in the life cycle event management.
      *
      * @param headerForm
      * the form that owns the shared header
      * @see IFormPart
      */
     protected void createHeaderContents(IManagedForm headerForm) {
     }
 }
